﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;

using System.Globalization;
using System.Text;
using System.Text.Json.Nodes;

namespace GitHubCopilotProxies.Handlers;

public class Utils
{
    public static async Task Help(HttpContext httpContext, [FromServices] EmbeddedFileProvider fileProvider)
    {
        var fileInfo = fileProvider.GetFileInfo("help.html");
        var ifModifiedSinceStr = httpContext.Request.GetTypedHeaders().IfModifiedSince?.ToString("r", CultureInfo.InvariantCulture);
        var lastModifiedStr = fileInfo.LastModified.ToString("r", CultureInfo.InvariantCulture);
        if (string.Equals(ifModifiedSinceStr, lastModifiedStr, StringComparison.OrdinalIgnoreCase))
        {
            httpContext.Response.StatusCode = StatusCodes.Status304NotModified;
            return;
        }
        httpContext.Response.ContentType = HtmlContentType;
        var typedHeaders = httpContext.Response.GetTypedHeaders();
        typedHeaders.CacheControl = new() { Public = true, MaxAge = TimeSpan.FromHours(1) };
        typedHeaders.LastModified = fileInfo.LastModified;
        using var stream = fileInfo.CreateReadStream();
        await stream.CopyToAsync(httpContext.Response.Body, httpContext.RequestAborted);
        await httpContext.Response.CompleteAsync();
    }

    static Lazy<string> ModelString = new Lazy<string>(() =>
    {
        const string modelsJson = """{"data":[{"capabilities":{"family":"gpt-3.5-turbo","limits":{"max_context_window_tokens":16384,"max_output_tokens":4096,"max_prompt_tokens":16384},"object":"model_capabilities","supports":{"streaming":true,"tool_calls":true},"tokenizer":"cl100k_base","type":"chat"},"id":"gpt-3.5-turbo","model_picker_enabled":false,"name":"GPT 3.5 Turbo","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-3.5-turbo-0613"},{"capabilities":{"family":"gpt-3.5-turbo","limits":{"max_context_window_tokens":16384,"max_output_tokens":4096,"max_prompt_tokens":16384},"object":"model_capabilities","supports":{"streaming":true,"tool_calls":true},"tokenizer":"cl100k_base","type":"chat"},"id":"gpt-3.5-turbo-0613","model_picker_enabled":false,"name":"GPT 3.5 Turbo","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-3.5-turbo-0613"},{"capabilities":{"family":"gpt-4o-mini","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4o-mini","model_picker_enabled":false,"name":"GPT-4o mini","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-mini-2024-07-18"},{"capabilities":{"family":"gpt-4o-mini","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4o-mini-2024-07-18","model_picker_enabled":false,"name":"GPT-4o mini","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-mini-2024-07-18"},{"capabilities":{"family":"gpt-4","limits":{"max_context_window_tokens":32768,"max_output_tokens":4096,"max_prompt_tokens":32768},"object":"model_capabilities","supports":{"streaming":true,"tool_calls":true},"tokenizer":"cl100k_base","type":"chat"},"id":"gpt-4","model_picker_enabled":false,"name":"GPT 4","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4-0613"},{"capabilities":{"family":"gpt-4","limits":{"max_context_window_tokens":32768,"max_output_tokens":4096,"max_prompt_tokens":32768},"object":"model_capabilities","supports":{"streaming":true,"tool_calls":true},"tokenizer":"cl100k_base","type":"chat"},"id":"gpt-4-0613","model_picker_enabled":false,"name":"GPT 4","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4-0613"},{"capabilities":{"family":"gpt-4o","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000,"vision":{"max_prompt_image_size":3145728,"max_prompt_images":1,"supported_media_types":["image/jpeg","image/png","image/webp","image/gif"]}},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4o","model_picker_enabled":true,"name":"GPT-4o","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-2024-05-13"},{"capabilities":{"family":"gpt-4o","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000,"vision":{"max_prompt_image_size":3145728,"max_prompt_images":1,"supported_media_types":["image/jpeg","image/png","image/webp","image/gif"]}},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4o-2024-05-13","model_picker_enabled":false,"name":"GPT-4o","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-2024-05-13"},{"capabilities":{"family":"gpt-4o","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4-o-preview","model_picker_enabled":false,"name":"GPT-4o","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-2024-05-13"},{"capabilities":{"family":"gpt-4o","limits":{"max_context_window_tokens":128000,"max_output_tokens":16384,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"gpt-4o-2024-08-06","model_picker_enabled":false,"name":"GPT-4o","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4o-2024-08-06"},{"capabilities":{"family":"text-embedding-ada-002","limits":{"max_inputs":256},"object":"model_capabilities","supports":{},"tokenizer":"cl100k_base","type":"embeddings"},"id":"text-embedding-ada-002","model_picker_enabled":false,"name":"Embedding V2 Ada","object":"model","preview":false,"vendor":"Azure OpenAI","version":"text-embedding-ada-002"},{"capabilities":{"family":"text-embedding-3-small","limits":{"max_inputs":512},"object":"model_capabilities","supports":{"dimensions":true},"tokenizer":"cl100k_base","type":"embeddings"},"id":"text-embedding-3-small","model_picker_enabled":false,"name":"Embedding V3 small","object":"model","preview":false,"vendor":"Azure OpenAI","version":"text-embedding-3-small"},{"capabilities":{"family":"text-embedding-3-small","object":"model_capabilities","supports":{"dimensions":true},"tokenizer":"cl100k_base","type":"embeddings"},"id":"text-embedding-3-small-inference","model_picker_enabled":false,"name":"Embedding V3 small (Inference)","object":"model","preview":false,"vendor":"Azure OpenAI","version":"text-embedding-3-small"},{"capabilities":{"family":"gpt-4-turbo","limits":{"max_context_window_tokens":128000,"max_output_tokens":4096,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"cl100k_base","type":"chat"},"id":"gpt-4-0125-preview","model_picker_enabled":false,"name":"GPT 4 Turbo","object":"model","preview":false,"vendor":"Azure OpenAI","version":"gpt-4-0125-preview"},{"capabilities":{"family":"o1","limits":{"max_context_window_tokens":128000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{},"tokenizer":"o200k_base","type":"chat"},"id":"o1-preview","model_picker_enabled":true,"name":"o1-preview (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-preview-2024-09-12"},{"capabilities":{"family":"o1","limits":{"max_context_window_tokens":128000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{},"tokenizer":"o200k_base","type":"chat"},"id":"o1-preview-2024-09-12","model_picker_enabled":false,"name":"o1-preview (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-preview-2024-09-12"},{"capabilities":{"family":"o1-mini","limits":{"max_context_window_tokens":128000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{},"tokenizer":"o200k_base","type":"chat"},"id":"o1-mini","model_picker_enabled":true,"name":"o1-mini (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-mini-2024-09-12"},{"capabilities":{"family":"o1-mini","limits":{"max_context_window_tokens":128000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{},"tokenizer":"o200k_base","type":"chat"},"id":"o1-mini-2024-09-12","model_picker_enabled":false,"name":"o1-mini (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-mini-2024-09-12"},{"capabilities":{"family":"o1-ga","limits":{"max_context_window_tokens":200000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{"structured_outputs":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"o1","model_picker_enabled":true,"name":"o1 (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-2024-12-17"},{"capabilities":{"family":"o1-ga","limits":{"max_context_window_tokens":200000,"max_prompt_tokens":20000},"object":"model_capabilities","supports":{"structured_outputs":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"o1-2024-12-17","model_picker_enabled":false,"name":"o1 (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o1-2024-12-17"},{"capabilities":{"family":"o3-mini","limits":{"max_context_window_tokens":200000,"max_output_tokens":100000,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"streaming":true,"structured_outputs":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"o3-mini","model_picker_enabled":true,"name":"o3-mini (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o3-mini-2025-01-31"},{"capabilities":{"family":"o3-mini","limits":{"max_context_window_tokens":200000,"max_output_tokens":100000,"max_prompt_tokens":64000},"object":"model_capabilities","supports":{"streaming":true,"structured_outputs":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"o3-mini-2025-01-31","model_picker_enabled":false,"name":"o3-mini (Preview)","object":"model","preview":true,"vendor":"Azure OpenAI","version":"o3-mini-2025-01-31"},{"capabilities":{"family":"claude-3.5-sonnet","limits":{"max_context_window_tokens":90000,"max_output_tokens":8192,"max_prompt_tokens":90000,"vision":{"max_prompt_image_size":3145728,"max_prompt_images":1,"supported_media_types":["image/jpeg","image/png","image/gif","image/webp"]}},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"claude-3.5-sonnet","model_picker_enabled":true,"name":"Claude 3.5 Sonnet (Preview)","object":"model","policy":{"state":"enabled","terms":"Enable access to the latest Claude 3.5 Sonnet model from Anthropic. [Learn more about how GitHub Copilot serves Claude 3.5 Sonnet](https://docs.github.com/copilot/using-github-copilot/using-claude-sonnet-in-github-copilot)."},"preview":true,"vendor":"Anthropic","version":"claude-3.5-sonnet"},{"capabilities":{"family":"claude-3.7-sonnet","limits":{"max_context_window_tokens":200000,"max_output_tokens":8192,"max_prompt_tokens":90000},"object":"model_capabilities","supports":{"parallel_tool_calls":true,"streaming":true,"tool_calls":true},"tokenizer":"o200k_base","type":"chat"},"id":"claude-3.7-sonnet","model_picker_enabled":true,"name":"Claude 3.7 Sonnet (Preview)","object":"model","policy":{"state":"enabled","terms":"Enable access to the latest Claude 3.7 Sonnet model from Anthropic. [Learn more about how GitHub Copilot serves Claude 3.7 Sonnet](https://docs.github.com/copilot/using-github-copilot/using-claude-sonnet-in-github-copilot)."},"preview":true,"vendor":"Anthropic","version":"claude-3.7-sonnet"},{"capabilities":{"family":"claude-3.7-sonnet-thought","limits":{"max_context_window_tokens":200000,"max_output_tokens":8192,"max_prompt_tokens":90000},"object":"model_capabilities","supports":{"streaming":true},"tokenizer":"o200k_base","type":"chat"},"id":"claude-3.7-sonnet-thought","model_picker_enabled":true,"name":"Claude 3.7 Sonnet Thinking (Preview)","object":"model","policy":{"state":"enabled","terms":"Enable access to the latest Claude 3.7 Sonnet model from Anthropic. [Learn more about how GitHub Copilot serves Claude 3.7 Sonnet](https://docs.github.com/copilot/using-github-copilot/using-claude-sonnet-in-github-copilot)."},"preview":true,"vendor":"Anthropic","version":"claude-3.7-sonnet-thought"},{"capabilities":{"family":"gemini-2.0-flash","limits":{"max_context_window_tokens":1000000,"max_output_tokens":8192,"max_prompt_tokens":128000,"vision":{"max_prompt_image_size":3145728,"max_prompt_images":1,"supported_media_types":["image/jpeg","image/png","image/webp","image/heic","image/heif"]}},"object":"model_capabilities","supports":{"streaming":true},"tokenizer":"o200k_base","type":"chat"},"id":"gemini-2.0-flash-001","model_picker_enabled":true,"name":"Gemini 2.0 Flash (Preview)","object":"model","policy":{"state":"enabled","terms":"Enable access to the latest Gemini models from Google. [Learn more about how GitHub Copilot serves Gemini 2.0 Flash](https://docs.github.com/en/copilot/using-github-copilot/ai-models/using-gemini-flash-in-github-copilot)."},"preview":true,"vendor":"Google","version":"gemini-2.0-flash-001"}],"object":"list"}""";
        var jsObj = JsonObject.Parse(modelsJson)!;
        var data = jsObj["data"]!.AsArray().AsEnumerable();
        void ModifyModelInfo(string id, string name, bool enabled)
        {
            var item = data.First(item => item!.AsObject()!["id"]!.ToString() == id)!.AsObject();
            item["name"] = name;
            item["model_picker_enabled"] = enabled;
        }
        bool alibailianEnabled = string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ALIBAILIAN_API_KEY")) == false;
        bool volcengineEnabled = string.IsNullOrEmpty(Environment.GetEnvironmentVariable("VOLCENGINE_API_KEY")) == false;
        ModifyModelInfo("gpt-4o", "DeepSeek V3 [DeepSeek] (gpt-4o)", true);
        ModifyModelInfo("o1", "通义千问-Plus [阿里云百炼] (o1)", true);
        ModifyModelInfo("o1-preview", "通义千问-Max [阿里云百炼] (o1-preview)", true);
        ModifyModelInfo("o1-mini", "DeepSeek R1 [火山方舟] (o1-mini)", volcengineEnabled);
        ModifyModelInfo("o3-mini", "DeepSeek V3 [火山方舟] (o3-mini)", volcengineEnabled);
        ModifyModelInfo("claude-3.5-sonnet", "DeepSeek V3 [阿里云百炼]", alibailianEnabled);
        ModifyModelInfo("claude-3.7-sonnet", "DeepSeek R1 [阿里云百炼]", alibailianEnabled);
        ModifyModelInfo("claude-3.7-sonnet-thought", "通义千问-QwQ-32B [阿里云百炼]", alibailianEnabled);
        ModifyModelInfo("gemini-2.0-flash-001", "Qwen2.5-Coder-32B-Instruct [硅基流动]", true);
        return jsObj.ToString();
    });
    public static async Task GetModels(HttpContext httpContext)
    {
        await httpContext.ResponseJsonAsync(ModelString.Value);
    }

    public static async Task GetPing(HttpContext httpContext)
    {
        httpContext.Response.ContentType = TextContentType;
        await httpContext.Response.WriteAsync("OK", Encoding.UTF8, httpContext.RequestAborted);
        await httpContext.Response.CompleteAsync();
    }

    public static async Task GetAgents(HttpContext httpContext)
    {
        await httpContext.ResponseJsonAsync("""{"agents":[]}""");
    }

    public static async Task GetV3meta(HttpContext httpContext)
    {
        await httpContext.ResponseJsonAsync("{}");
    }

    public static async Task GetCliv3(HttpContext httpContext)
    {
        httpContext.ResponseWithXOAuthScopes();
        const string jsonInfo = """{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","label_search_url":"https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}","notifications_url":"https://api.github.com/notifications","organization_url":"https://api.github.com/orgs/{org}","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_teams_url":"https://api.github.com/orgs/{org}/teams","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","topic_search_url":"https://api.github.com/search/topics?q={query}{&page,per_page}","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}""";
        await httpContext.ResponseJsonAsync(jsonInfo);
    }
}
